package com.uft.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;

import javax.xml.bind.JAXBException;

import org.apache.log4j.Logger;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;

public class JDOMUtil   {
	private static Logger _log = Logger.getLogger("com.ibx.wasadmin.utils.JDOMUtil");
	 public static String documentToString(Document doc) {
	        if (doc == null) return null;
	        XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
	        return out.outputString(doc);
	 }
	 public static String documentToStringDump(Document doc) {
	        if (doc == null) return null;
	        XMLOutputter out = new XMLOutputter(Format.getCompactFormat());
	        return out.outputString(doc);
	    }
	 public static String elementToString(Element e) {
	        if (e == null) return null ;
	        XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
	        return out.outputString(e);
	    }
	 public static String elementToStringDump(Element e) {
	        if (e == null) return null ;
	        XMLOutputter out = new XMLOutputter(Format.getCompactFormat());
	        return out.outputString(e);
	    }
	 public static Document stringToDocument(String s) {
	        try {
	           if (s == null) return null ;
	           
	           return new SAXBuilder().build(new StringReader(s));
	        }
	        catch (JDOMException jde) {
	            _log.error("JDOMException converting to Document, String = " + s , jde);
	            return null ;
	        }
	        catch (IOException ioe) {
	            _log.error("IOException converting to Document, String = " + s, ioe);
	            return null ;
	        }
	    }
	 public static Element stringToElement(String s) {
	        if (s == null) return null ;
	        Document doc = stringToDocument(s);
	        return doc.getRootElement();
	    }
	 public static Document fileToDocument(String path) {
	       try {
	           if (path == null) return null ;
	           _log.info("File Path:"+path);
	           return new SAXBuilder().build(new File(path));
	       }
	       catch (JDOMException jde) {
	           _log.error("JDOMException loading file into Document, filepath = " + path , jde);
	           return null ;
	       }
	       catch (IOException ioe) {
	           _log.error("IOException loading file into Document, filepath = " + path, ioe);
	           return null ;
	       }
	    }
	    /** saves a JDOM Document to a file */
     public static boolean documentToFile(Document doc, String path)   {
        try {
           FileOutputStream fos = new FileOutputStream(path);
           XMLOutputter xop = new XMLOutputter(Format.getPrettyFormat());
           xop.output(doc, fos);
           fos.flush();
           fos.close();
           return true;
      }
      catch (IOException ioe){
          _log.error("IO Exeception in saving Document to file, filepath = " + path, ioe) ;
          return false;
          
      }
   }
     public static List getElementByXpath(Document doc, String Xpath) throws JDOMException{
    	 _log.debug("Xpath: "+Xpath+" doc"+doc.toString());
    	 XPath x  = XPath.newInstance(Xpath);
    	 _log.debug("X: "+x);
    	  List list = x.selectNodes(doc);
    	  _log.debug("list: "+list.size()+" content: "+list);
    	 return list;
    	 
     }
     public static Element getSingleElementByXpath(Document doc, String Xpath) throws JDOMException{
    	 _log.debug("getSingleElementByXpath: "+Xpath);
    	 XPath x  = XPath.newInstance(Xpath);
    	 _log.debug("X: "+x);
    	 Element element = (Element)x.selectSingleNode(doc);
    	 return element;
     }
     public static String getValueByXpath(Document doc, String Xpath) throws JDOMException{
    	 _log.debug("Xpath: "+Xpath+" doc"+doc.toString());
    	 XPath x  = XPath.newInstance(Xpath);
    	 _log.debug("X: "+x);
    	Element e= (Element)x.selectSingleNode(doc);
    	if(e != null){
    		return e.getText();
    	}else{
    		return "";
    	}
    	 
     }
     public static List getElementByXpathNameSpace(Document doc, String Xpath) throws JDOMException{ 
    	 _log.debug("Xpath: "+Xpath+" doc"+doc.toString());
    	 XPath xpath  = XPath.newInstance(Xpath);
    	 xpath.addNamespace("ns", doc.getRootElement().getNamespaceURI());
    	 _log.debug("X: "+xpath);
    	  List list = xpath.selectNodes(doc);
    	  _log.debug("list: "+list.size()+" content: "+list);
    	 return list;
     }
     public static String getValueByXpathNameSpace(Document doc, String Xpath) throws JDOMException{
    	 _log.debug("Xpath: "+Xpath+" doc"+doc.toString());
    	 XPath x  = XPath.newInstance(Xpath);
    	 x.addNamespace("ns", doc.getRootElement().getNamespaceURI());
    	 _log.debug("X: "+x);
    	Element e= (Element)x.selectSingleNode(doc);
    	if(e != null){
    		return e.getText();
    	}else{
    		return "";
    	}
    	 
     }
     
    
     public static String getDefaultValueForType(String dataType) {
         if (dataType == null) return "null";
         else if (dataType.equalsIgnoreCase("boolean")) return "false" ;
         else if (dataType.equalsIgnoreCase("string")) return "" ;
         else return "0";
     }
     public static String encodeEscapes(String s) {
         if (s == null) return s;
         return s.replaceAll("&", "&amp;")
                 .replaceAll("<", "&lt;")                
                 .replaceAll(">", "&gt;")
                 .replaceAll("\"", "&quot;")
                 .replaceAll("'", "&apos;") ;
     }

     public static String decodeEscapes(String s) {
         if (s == null) return s;
         return s.replaceAll("&amp;", "&")
                 .replaceAll("&lt;","<")               
                 .replaceAll("&gt;", ">")
                 .replaceAll("&quot;","\"")
                 .replaceAll("&apos;", "'") ;
     }
     public static String formatXMLString(String s) {
         if (s == null) return null;
         if (s.startsWith("<?xml"))
             return documentToString(stringToDocument(s));
         else
             return elementToString(stringToElement(s));
     }

     public static String formatXMLStringAsDocument(String s) {
         return documentToString(stringToDocument(s));
     }

     public static String formatXMLStringAsElement(String s) {
         return elementToString(stringToElement(s));
     }
     public static HashMap getNodeIndex(Document inXmlDocument, 
             String uniqueAttribute) {

//Internal Variables
		int stackPointer=0;
		String locationId =null;
		Attribute tmpAttribute=null;
		Element thisElement=null;
		ListIterator deepestList=null;
		
		HashMap mappings = new HashMap();
		List stack = new Vector();
		
		//Get the list information for the entire document
		stack.add(inXmlDocument.getContent().listIterator());
		
		//Loop though the elements on list
		while (!stack.isEmpty()){
		
		//Get the last list on the stack
		deepestList = (ListIterator)stack.get(stack.size()-1);
		
		//Does this list have more elements?
		if (deepestList.hasNext()) {
		
		//if so Get Next element from this list
		thisElement = (Element)deepestList.next();
		
		//Add Mapping for this element to hashtable
		tmpAttribute = thisElement.getAttribute(uniqueAttribute);
		
		//Attibute can be null for non folder elements (e.g. root element) - if so ignore
		if (tmpAttribute!=null) {
		locationId= tmpAttribute.getValue();
		if ((locationId!=null)&&(locationId!="")) {
		mappings.put(locationId.toString(),thisElement);
		
		}
		} //end add mapping
		
		//does this list have children ?
		if(thisElement.getChildren().size() > 0){
		
		//if so add to the stack
		stackPointer++;
		stack.add(thisElement.getChildren().listIterator());
		}
		}
		else
		{
		//if not , remove this list from the stack
		stack.remove(stackPointer);
		stackPointer--;
		
		} // end if stack has more elements
		
		}
		
		return mappings;
}

/**
* gets all elements in the XML Document Being Passed in <BR>
* @param inXmlDocument to generated the hashmap from
* @return nodeList containing nodes
*/
public static HashSet getAllNodes(Document inXmlDocument) {

	//Internal Variables
	int stackPointer=0;
	int index=1;
	String locationId=null;
	Element currentElement=null;
	Element parentElement=null;
	Element thisElement=null;
	Attribute tmpAttribute=null;
	List elementList=null;
	ListIterator deepestList=null;
	
	HashMap mappings = new HashMap();
	HashSet nodeList = new HashSet();
	List stack = new Vector();              //Implements list interface
	
	//Get the list information for the entire document - kick start loop
	stack.add(inXmlDocument.getContent().listIterator());
	
	//Loop though the elements on list
	while (!stack.isEmpty()){
	
	//Get the last list on the stack
	deepestList = (ListIterator)stack.get(stack.size()-1);
	
	//Does this list have more elements?
	if (deepestList.hasNext()) {
	
	//if so Get Next element from this list
	thisElement = (Element)deepestList.next();
	
	// add this element to the list
	nodeList.add(thisElement);
	
	//does this list have children ?
	if(thisElement.getChildren().size() >0){
	
	//if so add to the stack
	stackPointer++;
	stack.add(thisElement.getChildren().listIterator());
	}
	}
	else
	{
	//if not , remove this list from the stack
	stack.remove(stackPointer);
	stackPointer--;
	
	} // end if stack has more elements
	
	}
	
	return nodeList;
}

/**
* Search for Nodes within Jdom Document<BR>
* @param inDocumentToSearch XML-JDOM Document  
* @param  uniqueIdentifierName we can use to index the document (unique
*    attribute like id or name present on the node we are searching for)
* @param uniqueIdentifierToFind in the indexed document
*/
public static Element findNode(Document inDocumentToSearch 
 , String uniqueIdentifierName
 , String uniqueIdentifierToFind) {

	// index document                        
	HashMap index = getNodeIndex(inDocumentToSearch, 
	          uniqueIdentifierName);
	             
	// Now get required element from index
	return (Element)index.get(uniqueIdentifierToFind);
	     

}
public static boolean checkExists(List<Element> source, Element toCheck){
	if(source.size()== 0){
		return false;
	}else{
		
		for(int i=0; i<source.size();i++){
			Element sElement=source.get(i);
			if(sElement.equals(toCheck)){
				return true;
			}
		}
		return false;
	}
}
public static boolean isNullAndEmpty(String str){
	if(str != null && !str.equalsIgnoreCase("")){
		return false;
	}
	return true;
}
public static void main(String[] args)
{
	Document doc = fileToDocument("/Users/bushan/Downloads/sample.xml");
	try {
		getElementByXpathNameSpace(doc, "/ns:xml/ns:ProcessDefinition/ns:JVM/ns:customProperty[ns:name='TEST']");
	} catch (JDOMException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}
}
